home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Archive / Graphics / QuickDraw GX / GX->PostScript Sample / GXToPostScript / Imaging Engine / PathLimit.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  10.8 KB  |  403 lines  |  [TEXT/MPS ]

  1. /*
  2.      File:        PathLimit.c
  3.  
  4.      Contains:    QuickDraw GX to PostScript conversion code.
  5.                          Routines in here deal with splitting shapes
  6.                         up into pieces that do not exceed the stinky
  7.                         PostScript path limit.
  8.  
  9.      Version:    Technology:    Quickdraw GX 1.1.x
  10.       
  11.      Copyright:    © 1990-1997 by Apple Computer, Inc., all rights reserved. 
  12. */
  13.  
  14. #include "GXToPSBuildConfig.h"
  15. #include <GXGraphics.h>
  16.  
  17. #include "PublicPostScriptIE.h"
  18. #include "ShapeUtilities.h"
  19. #include "Private.h"
  20.  
  21. #ifdef resumeLabel
  22.     #undef resumeLabel
  23. #endif
  24. #define resumeLabel(exception)
  25.  
  26. /***********************************
  27.     PSContPathPoints:
  28.     
  29.     count number of points.  Since the number
  30.     that will be used up by PostScript is different
  31.     than gx graphics, we must count ourselves.  This is due
  32.     to the fact that we use cubics in PostScript and
  33.     also that the gx graphics has implied points which must
  34.     be accounted for.
  35.     
  36.     The code is the same code as is used to output
  37.     path data
  38.     
  39. *************************************/
  40. long PSCountPathPoints( gxShape theShape);
  41. long PSCountPathPoints( gxShape theShape)
  42.     {
  43.         Ptr                                                        inPath;                            // We must walk through the Paths structure
  44.         gxShapeAttribute                            theAttributes;
  45.         long                                                    i, pointIndex;
  46.         long                                                    size;
  47.         long                                                    firstIndex, lastIndex;    // Index of first and last point ON curve.
  48.         Boolean                                                closeIt;                                // Is it open or closed.
  49.         long                                                    nContours;                            // Number of contours.
  50.         long                                                    nPoints;                                // Number of points in contour.
  51.         register unsigned long*                controlBitLong;                    // Pointer to control bits.
  52.         register unsigned long                cBitMask;                                // Mask for reading control bits.
  53.         unsigned long                                    lastBitMask;                        // Mask for last point in contour.
  54.         long                                                    cBitSize;                                // Number of longs for control bits.
  55.         short                                                    qIndex;                                    // Indicates #points in curve segment so far.
  56.         Boolean                                                isOff;                                    // On the curve or off the curve.
  57.         Boolean                                                firstIsOn, lastIsOn;
  58.         long                                                    totalPoints = 0;
  59.         
  60.         
  61.         /* If it is any fill other than frameFill we must close each contour */
  62.  
  63.         closeIt = !(GXGetShapeFill(theShape) == gxFrameFill);
  64.         
  65.         /***********
  66.             Make sure we have access to the shape data structure,
  67.             and then get it
  68.         ***********/        
  69.         theAttributes = GXGetShapeAttributes(theShape);
  70.         GXSetShapeAttributes(theShape, theAttributes | gxDirectShape);
  71.         
  72.         GXLockShape(theShape);
  73.         
  74.         inPath = (Ptr)GXGetShapeStructure(theShape, &size);            //Get a pointer to the structure.
  75.         check(inPath);
  76.         
  77.         nContours = ((gxPaths*)inPath)->contours;                                    //Get the number of countours.
  78.         inPath += sizeof(long);                                                                    //Move pointer past contours field.
  79.                 
  80.  
  81.         /** Now count points in all of the contours **/
  82.  
  83.         for (i = 0; i < nContours; i++) {        // Count each of the contours.
  84.         
  85.             nPoints = *(long*)inPath;                                            // Get the number of points for this contour.
  86.             inPath += sizeof(long);                                                // Move to the data.
  87.             
  88.             if (nPoints > 0) {
  89.             
  90.                 controlBitLong = (unsigned long*)inPath;            // Get to the control bits.
  91.                 
  92.                 cBitSize = (nPoints + 31) / 32;                                // Compute the size of control bits in longs.
  93.                     
  94.                 inPath += cBitSize * sizeof(long);                        // Skip past control bits.
  95.                                 
  96.                 cBitMask = 0x80000000U;                                                // Initilize the mask for reading bits.
  97.                 
  98.                 lastBitMask = 0x80000000U >> ((nPoints-1) & 0x0000001F);                            // Mod 32
  99.                 
  100.                 
  101.                 /** Compute the first and last point on the curve **/
  102.                 
  103.                 firstIsOn =  ((*controlBitLong & cBitMask) == 0);
  104.                 lastIsOn = ( ( *(controlBitLong + cBitSize - 1) & lastBitMask) == 0);
  105.                 
  106.                 if (firstIsOn && lastIsOn) {    // They both are on.
  107.                 
  108.                     firstIndex = 0;
  109.                     lastIndex = nPoints;
  110.                     NEXTBIT(isOff, controlBitLong, cBitMask);            // Read bit for 1st point, set up for next.
  111.                     
  112.                 } else if (firstIsOn) {                // first was on, last was off
  113.                     
  114.                     firstIndex = 0;
  115.                     lastIndex = nPoints + 1;
  116.                     NEXTBIT(isOff, controlBitLong, cBitMask);            // Read bit for 1st point, set up for next.
  117.                 
  118.                 } else if (lastIsOn) {                // last was on, first is off
  119.                     
  120.                     lastIndex = nPoints;
  121.                     firstIndex = -1;
  122.                 
  123.                 } else {                                            // they were both off
  124.                 
  125.                     firstIndex = -1;
  126.                     lastIndex = nPoints + 1;
  127.                                                     
  128.                 } //end if
  129.                 
  130.                 
  131.                 /*** count the contour ****/
  132.                 
  133.                 qIndex = 0;
  134.                 totalPoints += 1;                    // the first point in the contour.                
  135.     
  136.                 // Loop over all points but the first and last ON the curve.
  137.                 
  138.                 NEXTBIT(isOff, controlBitLong, cBitMask);        // Check the first point in the looping.
  139.                 pointIndex = firstIndex + 1;
  140.                 while (pointIndex < (lastIndex - 1)) {            // I know, should cache lastPointIndex-1
  141.                                     
  142.                     if (!isOff) {                                    // If the next point is on the curve:
  143.                     
  144.                         if ( qIndex == 0) {                    // If we have only q0, then do a line and start over.
  145.                                                 
  146.                             totalPoints += 1;                    // add a line segment.
  147.  
  148.                             ++pointIndex;
  149.     
  150.                             NEXTBIT(isOff, controlBitLong, cBitMask);
  151.                             
  152.                         } else {                                        // We must have q0 and q1, do a curve: q0, q1, q2
  153.                         
  154.                             totalPoints += 3;                    // Add a curve segment.
  155.                             qIndex = 0;
  156.                             ++pointIndex;
  157.                             NEXTBIT(isOff, controlBitLong, cBitMask);
  158.                         
  159.                         }//end if
  160.                     
  161.                     } else {
  162.                     
  163.                         if (qIndex == 0) {                    // If we only have one point so far, this becomes 2nd.
  164.                         
  165.                             qIndex = 1;
  166.                             NEXTBIT(isOff, controlBitLong, cBitMask);
  167.                             ++pointIndex;
  168.                         
  169.                         } else {                                        // We had 2 points, interpolate to get 3rd and to a curve
  170.                                                     
  171.                             totalPoints += 3;                    // Add a curve segment.
  172.                             qIndex = 0;
  173.                         
  174.                         }//end if
  175.                     
  176.                     }//end if
  177.                 
  178.                 }//end while
  179.                                 
  180.     
  181.                 /** Now handle the last point that is ON the curve in the contour **/
  182.                 
  183.                 if (qIndex == 0) {                // If we only had one point so far, Do a line.
  184.                 
  185.                     totalPoints += 1;                    // Add a line segment.
  186.                 
  187.                 } else {                                    // Else, we must have had 2 points so far, Do a curve.
  188.                 
  189.                     totalPoints += 3;                    // Add a curve segment.
  190.                 
  191.                 }//end if
  192.                 
  193.                 if (closeIt)                
  194.                     totalPoints += 1;                    // Add a line segment.
  195.                     
  196.                 
  197.                 /** Point into the next contour **/
  198.                 
  199.                 inPath += nPoints * sizeof(gxPoint);    // Next contour is where our next point is pointing to.
  200.                     
  201.             }//end if
  202.         
  203.         }//endo for i
  204.         
  205.         GXSetShapeAttributes(theShape, theAttributes);
  206.         GXUnlockShape(theShape);
  207.         
  208. failed_Output:
  209. failed_KeepDirect:        
  210.         
  211.         return(totalPoints);
  212.     
  213.     }//PSCountPathPoints
  214.  
  215. //<FF>
  216. /***********************************
  217.     PSCountCubicSynonymPoints:
  218.     
  219.     count number of points.
  220.     
  221.     The code is the same code as is used to output
  222.     cubic synonym data
  223.     
  224. *************************************/
  225. long PSCountCubicSynonymPoints(gxShape theShape);
  226. long PSCountCubicSynonymPoints(gxShape theShape)
  227.     {
  228.         gxTag                cubicTag;
  229.         Ptr                    cubicData;
  230.         Ptr                    inCubic, endCubic;
  231.         long                dataSize;
  232.         short                instruction;
  233.         long                nPoints = 0;
  234.                 
  235.         GXGetShapeTags(theShape, gxCubicSynonymTag, 1, 1, &cubicTag);
  236.         
  237.         GXLockTag(cubicTag);
  238.         cubicData = (Ptr)GXGetTagStructure(cubicTag, &dataSize);
  239.     
  240.         inCubic = cubicData;
  241.         endCubic = cubicData + dataSize;
  242.         
  243.         while(inCubic < endCubic) {
  244.         
  245.             instruction = (short)(*inCubic) & gxCubicInstructionMask;
  246.             inCubic += sizeof(short);
  247.         
  248.             switch(instruction) {
  249.             
  250.                 case gxMoveToFlag:
  251.                     ++nPoints;
  252.                     inCubic += sizeof(gxPoint);
  253.                     break;
  254.                 
  255.                 case gxLineToFlag:
  256.                     ++nPoints;                
  257.                     inCubic += sizeof(gxPoint);
  258.                     break;
  259.                     
  260.                 case gxCurveToFlag:
  261.                     inCubic += 3 * sizeof(gxPoint);
  262.                     nPoints += 3;
  263.                     break;
  264.                     
  265.                 case gxClosePathFlag:
  266.                     ++nPoints;
  267.                     break;
  268.             
  269.             }//end switch
  270.         
  271.         }//end while
  272.             
  273.         GXUnlockTag(cubicTag);
  274.     
  275.         return(nPoints);    
  276.     
  277.     }//PSCountCubicSynonymPoints
  278.  
  279.  
  280. //<FF>
  281. /****************************************
  282.  
  283.     Routine PSCountShapePoints:
  284.     
  285.     Routine is wrapper with same interface as
  286.     CountShapePoints.  It calls the PostScript version
  287.     (above) for paths.
  288.     
  289.     This routine gets passed to DissectPath for counting.
  290.     
  291. *****************************************/
  292. OSErr PSCountShapePoints(gxShape aShape, long contour, long *numPoints)
  293.     {        
  294.         switch(GXGetShapeType(aShape)) {
  295.         
  296.             case gxPointType:
  297.             case gxLineType:
  298.                 *numPoints = 2;
  299.                 break;
  300.             
  301.             case gxCurveType:
  302.                 *numPoints = 4;
  303.                 break;
  304.                 
  305.             case gxRectangleType:
  306.                 *numPoints = 4;
  307.                 break;
  308.             
  309.             case gxPolygonType:
  310.                 *numPoints = GXCountShapePoints(aShape, contour);
  311.                 if (GXGetShapeFill(aShape) == gxClosedFrameFill)
  312.                     *numPoints += GXCountShapeContours(aShape);                                    // one point per closepath.
  313.                 
  314.                 break;
  315.                 
  316.             case gxPathType:
  317.                 if (GXGetShapeTags(aShape, gxCubicSynonymTag, 1, 1, nil))
  318.                     *numPoints = PSCountCubicSynonymPoints(aShape);
  319.                 else
  320.                     *numPoints = PSCountPathPoints(aShape);
  321.                 break;
  322.             
  323.             default:                        // All other types take up no predictable PostScript path space.
  324.                 *numPoints = 0;
  325.                 break;        
  326.         
  327.         }//end switch
  328.                 
  329.         return( noErr );
  330.     
  331.     }//PSCountShapePoints;
  332.     
  333.  
  334.  
  335. //<FF>
  336. /********************************************
  337.  
  338.     Routine DissectShape:
  339.  
  340.     Routine to make sure a shape does not exceed
  341.     the path limit.      If there are very few points
  342.     left in the pathlimit at the current level (or 
  343.     even negative - can happen when clips are really
  344.     large because we always just subtract clip size
  345.     from current state.) we will go to blast and
  346.     pray mode which may cause limitchecks.  Otherwise
  347.     we will try shape-ops.
  348.     
  349. *********************************************/
  350. #define kMinPointsDissect 50
  351. OSErr DissectShape(TIEGlobalsHdl hIEGlobals, gxShape *theShape)
  352.     {
  353.         OSErr                            status = noErr;
  354.         TIEGlobalsPtr            pGlobals;
  355.         long                            pointsAvailable, pointCount;
  356.         gxShape                        shapeCopy;
  357.         
  358.         pGlobals = *hIEGlobals;
  359.         
  360.         // Don't need to bother for noFill shapes.
  361.         if ( GXGetShapeFill(*theShape) == gxNoFill )
  362.             return(noErr);
  363.         
  364.         
  365.         if ( GXGetShapeFill(*theShape) == gxNoFill)
  366.             return(noErr);
  367.  
  368.         if (pGlobals->gStateDepth == -1)
  369.             pointsAvailable = pGlobals->params.pathLimit;
  370.         else
  371.             pointsAvailable = pGlobals->gStateNest[pGlobals->gStateDepth].pointsAvail;
  372.             
  373.         #if DEBUGLEVEL > 1
  374.             if (pointsAvailable < kMinPointsDissect)
  375.                 dprintf(trace, "Really low on path space: %d, disabling shape dissection - good luck!", pointsAvailable);
  376.         #endif
  377.                 
  378.         /******
  379.             If the shape is biggern than the current pathlimit 
  380.             and the current path limit is greater than kMinPointsDissect, 
  381.             try to dissect - otherwise we will just blast and pray for no limitchecks.
  382.         *****/
  383.         status = _PSCountShapePoints(*theShape, 0, &pointCount);
  384.         nrequire(status, failed_count);
  385.         
  386.         if ((pointsAvailable > kMinPointsDissect) && (pointCount > pointsAvailable)) {
  387.         
  388.             nrequire(status = DupShapeIfNecessary(*theShape, &shapeCopy), failed_Dup);
  389.             *theShape = shapeCopy;
  390.  
  391.             status = ShUDissectPath(*theShape, pointsAvailable, true, &_PSCountShapePoints);        
  392.             nrequire(status, failed_Split);
  393.             
  394.         }//end if
  395.  
  396. failed_Split:        
  397. failed_Dup:
  398. failed_count:
  399.  
  400.         return(status);
  401.     
  402.     }//DissectShape
  403.